YUI.add("participantBadge", function(Y) {
    var Lang = Y.Lang,
        Node = Y.Node,
        ParticipantEvent = Y.ParticipantEvent; 
    
    /* ParticipantBadgeController constructor */
    var ParticipantBadge = function(config) {
        ParticipantBadge.superclass.constructor.apply(this, arguments);
    } 
    ParticipantBadge.NAME = "participantBadge";
  
 	
    /* Static constants */
    ParticipantBadge.OFFSET_X = -330;
    ParticipantBadge.OFFSET_Y = -60;
    ParticipantBadge.OFFSCREEN_X = -10000;
    ParticipantBadge.OFFSCREEN_Y = -10000;
 
    /* Default ParticipantBadge Attributes */
    ParticipantBadge.ATTRS = {
        model : {
        	value: new Y.ParticipantModel(null)
        },
        /* 
         * The participantbadge content. This can either be a fixed content value, 
         * or a map of id-to-values, designed to be used when a single
         * participantbadge is mapped to multiple trigger elements.
         */
        content : {
            value: null
        },
 
        /* 
         * The set of nodes to bind to the participantbadge instance. Can be a string, 
         * or a node instance.
         */
        triggerNodes : {
            value: null,
            setter: function(val) {
                if (val && Lang.isString(val)) {
                    val = Node.all(val);
                } 
                return val;
            }
        },
 
        /*
         * The delegate node to which event listeners should be attached.
         * This node should be an ancestor of all trigger nodes bound
         * to the instance. By default the document is used.
         */
        delegate : {
            value: null,
            setter: function(val) {
                return Node.get(val) || Node.get("document");
            }
        },
 
       
        showDelay : {
            value:500
        },      
        hideDelay : {
            value:50
        },     
        autoHideDelay : {
            value:4000
        },
        visible : {
            value:false
        },
        xy: {
            value:[ParticipantBadge.OFFSCREEN_X, ParticipantBadge.OFFSCREEN_Y]
        }
    };
 
    /* Extend the base Widget class */
    Y.extend(ParticipantBadge, Y.Widget, {
 		 
        /*
         * Initialization Code: Sets up privately used state
         * properties, and publishes the events ParticipantBadge introduces
         */
        initializer : function(config) { 
        	
 			this._view = new Y.ParticipantBadgeView({
        		container:this.get("contentBox")
        	});
 			//trigger is used arbitrarely. I could use triggerrrrrrr for example and it would have worked 
 			//perfectly fine. This is used to tag the the nodes that are supposed to be triggers.
            this._triggerClassName = this.getClassName("trigger");
 			
            // Currently bound trigger node information
            this._currTrigger = {
                node: null,
                title: null,
                buddyInfo: null,
                mouseX: ParticipantBadge.OFFSCREEN_X,
                mouseY: ParticipantBadge.OFFSCREEN_Y
            };
 
            // Event handles - mouse over is set on the delegate
            // element, mousemove and mouseout are set on the trigger node
            this._eventHandles = {
                delegate: null,
                contentReady: null,
                listScroll:null,
                trigger:{
                    mouseMove : null,
                    mouseOut: null                  
                },
                popup:{
                	mouseMove : null,
                    mouseOut: null
                } 
            };
 
            // Show/hide timers
            this._timers = {
                show: null,
                hide: null
            };
 
            // Publish events introduced by ParticipantBadge. Note the triggerEnter event is preventable,
            // with the default behavior defined in the _defTriggerEnterFn method 
            this.publish("triggerEnter", {defaultFn: this._defTriggerEnterFn, preventable:true});
            this.publish("triggerLeave", {preventable:false}); 
            
        },
 
        /*
         * Destruction Code: Clears event handles, timers,
         * and current trigger information
         */
        destructor : function() {
            this._clearCurrentTrigger();
            this._clearTimers();
            this._clearHandles();
        },
 
        /*
         * bindUI is used to bind attribute change and dom event
         * listeners
         */
        bindUI : function() {
            this.after("delegateChange", this._afterSetDelegate);
            this.after("nodesChange", this._afterSetNodes);			
            this._eventHandles.listScroll =  Y.on(ParticipantEvent.ListView.LIST_SCROLL, Y.bind(this._hideParticipantBadge, this),  this.get("delegate")); 
            this._bindDelegate();
            this._bindPopup();             
        }, 
        
        /*
         * syncUI is used to update the rendered DOM, based on the current
         * ParticipantBadge state
         */
        syncUI : function() {
            this._uiSetNodes(this.get("triggerNodes"));
        },
 
       
        /*
         * Gets the closest ancestor of the given node,
         * which is a participantbadge trigger node
         */
        getParentTrigger : function(node) {  
            return (node.hasClass(this._triggerClassName)) ? node : node.ancestor(function(node) {node.hasClass(this._triggerClassName)});
        },
 
        /*
         * Default attribute change listener for 
         * the triggerNodes attribute
         */
        _afterSetNodes : function(e) {
            this._uiSetNodes(e.newVal);
        },
  		/*
         * Updates the rendered DOM to reflect the
         * set of trigger nodes passed in
         */
        _uiSetNodes : function(nodes) {
            if (this._triggerNodes) {
                this._triggerNodes.removeClass(this._triggerClassName);
            }
 
            if (nodes) {
                this._triggerNodes = nodes;
                this._triggerNodes.addClass(this._triggerClassName);
            }
        },
        /*
         * Default attribute change listener for 
         * the delegate attribute
         */
        _afterSetDelegate : function(e) {
            this._bindDelegate(e.newVal);
        },
 		/*
         * Attaches the default mouseover DOM listener to the 
         * current delegate node
         */
        _bindDelegate : function() {
            var eventHandles = this._eventHandles;
 
            if (eventHandles.delegate) {
                eventHandles.delegate.detach();
                eventHandles.delegate = null;
            } 
            eventHandles.delegate = Y.on("mouseover", Y.bind(this._onDelegateMouseOver, this), this.get("delegate"));
            
            
        }, 
         _onContentMouseOver : function(e) {   
            this._clearTimers();
         },
        /*
         * Default mouse over DOM event listener.
         * 
         * Delegates to the _enterTrigger method,
         * if the mouseover enters a trigger node.
         */
        _onDelegateMouseOver : function(e) { 

            var node = this.getParentTrigger(e.target);
          
            if(!node )
            	return;
            	
            if(node.compareTo(this._currTrigger.node))
            {
            	this._clearTimers();
            	return;
            }
           	this._hideParticipantBadge();
            this._currTrigger.node = node;
            this._enterTrigger(node);
        },
 
 		
 
        /*
         * Default mouse out DOM event listener
         * 
         * Delegates to _leaveTrigger if the mouseout
         * leaves the current trigger node
         */
        _onNodeMouseOut : function(e) {
        	if(!e)return;
            var to = e.relatedTarget;
            var trigger = e.currentTarget;
 			 
 				
          	if (!trigger.contains(to)) {
            	this._leaveTrigger(trigger);
         	}
        },
 
        /*
         * Default mouse move DOM event listener
         */
        _onNodeMouseMove : function(e) {
            this._overTrigger();

        },
 
        /*
         * Default handler invoked when the mouse enters
         * a trigger node. Fires the triggerEnter
         * event which can be prevented by listeners to 
         * show the participantbadge from being displayed.
         */
        _enterTrigger : function(node) { 
            this._setCurrentTrigger(node);
            this.fire("triggerEnter", {node:node});
        },
 
        /*
         * Default handler for the triggerEvent event,
         * which will setup the timer to display the participantbadge,
         * if the default handler has not been prevented.
         */
        _defTriggerEnterFn : function(e) {
            var node = e.node;
            if (!this.get("disabled")) {
                this._clearTimers();
                var delay = (this.get("visible")) ? 0 : this.get("showDelay");
                this._timers.show = Y.later(delay, this, this._showParticipantBadge, [node]);
            }
        },
 
        /*
         * Default handler invoked when the mouse leaves
         * the current trigger node. Fires the triggerLeave
         * event and sets up the hide timer
         */
        _leaveTrigger : function(node) {
        	 
            this.fire("triggerLeave");
 
            this._clearTimers();
  
            this._timers.hide = Y.later(this.get("hideDelay"), this, this._hideParticipantBadge);
        },
 
        /*
         * Default handler invoked for mousemove events
         * on the trigger node. 
         */
        _overTrigger : function() {
           // this._currTrigger.mouseX = x;
           // this._currTrigger.mouseY = y;
        },
 
        /*
         * Shows the participantbadge, after moving it to the current mouse
         * position.
         */
        _showParticipantBadge : function(node) {
            var x = this._currTrigger.mouseX;
            var y = this._currTrigger.mouseY; 
           
            this.move(x + ParticipantBadge.OFFSET_X, y + ParticipantBadge.OFFSET_Y);
            
            this.show();
            this._clearTimers();
 			
            this._timers.hide = Y.later(this.get("autoHideDelay"), this, this._hideParticipantBadge);
            
        },
 
        /*
         * Hides the participantbadge, after clearing existing timers.
         */
        _hideParticipantBadge : function() {
        	
            this._clearCurrentTrigger();
            this._clearTimers(); 
            this.hide(); 
        },
  
         /*
         * Sets the events that fire when the mouse is over the popup
         * and when it leaves it.
         */
 		_bindPopup: function() {            
 			this._eventHandles.popup.mouseMove = Y.on("mouseover", Y.bind(this._onContentMouseOver, this), this.get("contentBox")  );
            this._eventHandles.popup.mouseOut = Y.on("mouseout", Y.bind(this._onNodeMouseOut, this), this.get("contentBox") );
 		},
        /*
         * Set the currently bound trigger node information, clearing 
         * out the title attribute if set and setting up mousemove/out 
         * listeners.
         */
        _setCurrentTrigger : function(node) {
 
            var currTrigger = this._currTrigger,
            triggerHandles = this._eventHandles.trigger;
                 
            triggerHandles.moueMove = Y.on("mousemove", Y.bind(this._onNodeMouseMove, this), node);
            triggerHandles.mouseOut = Y.on("mouseout", Y.bind(this._onNodeMouseOut, this), node);
              			
            currTrigger.mouseX = node.getX() ;
            currTrigger.mouseY = node.getY(); 
             /* EVENTS */ 
 			Y.fire(ParticipantEvent.Badge.ROLLED_OVER  , node.get('id') );
        },
 
        /*
         * Clear out the current trigger state, restoring
         * the title attribute on the trigger node, 
         * if it was originally set.
         */
        _clearCurrentTrigger : function() {
 
            var currTrigger = this._currTrigger,
                triggerHandles = this._eventHandles.trigger;
 
	            if (currTrigger.node) {
	                var node = currTrigger.node;
	                var title = currTrigger.title || "";
	 
	                currTrigger.node = null;
	                currTrigger.title = "";
	 			
            	var eventHandles = this._eventHandles;
            	
            	if (eventHandles.trigger.mouseOut) {
                	eventHandles.trigger.mouseOut.detach();
                	
            	}
            	if (eventHandles.trigger.mouseMove) {
                	eventHandles.trigger.mouseMove.detach();
            	}
            
            
	            /*
	            if (eventHandles.popup.mouseMove) {
	                eventHandles.popup.mouseMove.detach();
	                eventHandles.popup.mouseMove = null;
	            }
	            if (eventHandles.popup.mouseOut) {
	                eventHandles.popup.mouseOut.detach();
	                eventHandles.popup.mouseOut = null;
	                
	            } 
	            * */
 
            }
        },
 
        /*
         * Cancel any existing show/hide timers
         */
        _clearTimers : function() {
            var timers = this._timers;
            if (timers.hide) {
                timers.hide.cancel();
                timers.hide = null;
            }
            if (timers.show) {
              timers.show.cancel();
              timers.show = null;
            }
        },
 
        /*
         * Detach any stored event handles
         */
        _clearHandles : function() {
            var eventHandles = this._eventHandles;
 
            if (eventHandles.delegate) {
                eventHandles.delegate.detach();
            }
            if(this._eventHandles.contentReady)
            	eventHandles.contentReady.detach();
            	
            if (eventHandles.popup.mouseMove) {
                eventHandles.popup.mouseMove.detach();
            }
            if (eventHandles.popup.mouseOut) {
                eventHandles.popup.mouseOut.detach();
            }
            if (eventHandles.delegate) {
                eventHandles.delegate.detach();
            }
            if (eventHandles.trigger.mouseOut) {
                eventHandles.trigger.mouseOut.detach();
            }
            if (eventHandles.trigger.mouseMove) {
                eventHandles.trigger.mouseMove.detach();
            } 
            if(eventHandles.listScroll)
            	eventHandles.listScroll.detach();
        }
    });
     // dynamic:false = Modify the existing Tooltip class
    ParticipantBadge = Y.Base.build(ParticipantBadge.NAME, ParticipantBadge, [Y.WidgetPosition, Y.WidgetStack], {dynamic:false});
 
	Y.ParticipantBadge = ParticipantBadge; 
//});
} , 0.1 );